-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow "half" rating selection #2764
Conversation
Value is now set as a double that is coerced to a multiple of 0.5 within the Min/Max bounds. The colors are currently hardcoded, this needs to be addressed. Unit tests should also be added for the coercion.
Fixed issue where the first rating button could not be halfway selected. It is worth noting that valid values are actually values between Min-1 and Max (in multiples of 0.5)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great work, thank you for taking it on. A couple of suggestions.
First, I think we should make it an opt-in option for users clicking on the rating bar and getting fractional values. I think one way to accomplish this would be a property similar to the TickFrequency
of the slider where the developer can indicate the level of precision that is desired.
As for getting the colors and setting it up. I think we might be able to support more than just 0.5 by leveraging some attached properties and a custom MultiValueConverter
.
Here is a small sample I put together using a slider.
This XAML is using the Tag property, but we could create any number of internal attached/dependency properties to support this.
<Slider
Minimum="0"
Maximum="50"
Value="35"
Tag="{DynamicResource PrimaryHueMidBrush}">
<Slider.Foreground>
<MultiBinding Converter="{StaticResource LinearBackgroundConverter}">
<Binding Path="Tag" RelativeSource="{RelativeSource Self}"/>
<Binding Path="Value" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Slider.Foreground>
</Slider>
Then the converter would look something like this:
public object? Convert(object?[]? values, Type targetType, object parameter, CultureInfo culture)
{
//TODO add orientation as another parameter (might also need min/max to derive percentage)
if (values?.Length == 2 &&
values[0] is SolidColorBrush brush &&
values[1] is double value)
{
value /= 50;
return new LinearGradientBrush()
{
StartPoint = new Point(0, 0.5),
EndPoint = new Point(1, 0.5),
GradientStops = new()
{
new GradientStop { Color = Colors.Fuchsia, Offset = value },
new GradientStop { Color = brush.Color, Offset = value }
}
};
}
return null;
}
I think if we do something like this, it could also support more than just half values. Thoughts?
public class RatingBarTests | ||
{ | ||
[StaTheory] | ||
[InlineData(-5, 0.0)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the expected value here be 1.0 to match the Min?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well hidden in my commit comments, I left this little comment:
"It is worth noting that valid values are actually values between Min-1 and Max (in multiples of 0.5)"
I agree this is somewhat strange, and I will work on changing the behavior.
It should however be noted that the implementation before this PR did not have any coercion (which is strange for a "range bound" control IMO), and thus allowed you to set any value.
In any case, the first button represents the Min
value today, and that is a little strange because that actually means you should not be able to set a rating less than 1 star when Min
=1; why should it not be allowed to set 0 stars (although difficult to do with the mouse!)? Anyway, I will see if I can rework this into something a little more intuitive while preserving back-compat.
Great idea with the My only concern about opening up for |
I agree with the "supported" problem. I suspect that most consumers that use small increments will likely also set them to readonly (and I suspect bind the value to a TextBlock or similar to show a numeric value). I do like the idea of allowing the user to see the bound value on hover or press. I think some interaction that is similar to how the slider does it might be nice. Though I would say that displaying the value should be an opt-in behavior. |
Refactored into opt-in for fractional values. Fractional increments are now also configurable via the ValueIncrements DP.
Positioning of tooltip still missing
I have reworked the PR a bit to include opt-in features for fractional values (freely set), and preview of value being selected. See the updated PR description for details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really awesome work! Thank you
@Keboo Thanks for the feedback on this PR. I have reworked this PR based on your comments, and as such the changes are a bit more extensive; so grab a Mountain Dew before you read any further :-)
The PR now covers this:
Slider
but works on hover in this case.ValueIncrements
property (double
) which can have a value betweendouble.Epsilon
and 1.0. A value of 1.0 - which is the default - effectively means that fractional values are disabled. Specifying a value where less than 1.0 where 1 is not a multiple of said value (e.g. 0.75) works, but is not really useful. Perhaps the coercion ofValueIncrements
should ensure that the 1 is a multiple of the value being set. Thoughts?IMultiValueConveters
, and placed them as nested classes in theRatingBar
class because they are specifically made for that control. Let me know if you normally do it in a different manner.RatingBar.Orientation
andRatingBar.FlowDirection
Funny note:
The original
RatingBar
does not coerce its value, and thus you can set anything for theValue
property. This is probably also needed, because with Min=1 and Max=5 you can effectively not (with the mouse at least) set a rating of "0 stars".With fractional values enabled, I had to change this a bit, so in cases like that you would typically set Min=0 (instead of 1), which then means that you can partially select the first star; i.e. set a value between 0 and 1. In this case you can give a rating of "0 stars" because the coercion will eventually give you the value 0 if your mouse is close enough to the left edge of the first
RatingBarButton
.Screen captures (GIFs) of the new opt-in features can be seen below:
Original PR text:
Partial fix for #2073
IMPORTANT:
Correct theming colors need to be applied in MaterialDesignTheme.RatingBar.xaml resources defined in the top of the file. @Keboo do you have good suggestions on how to get these colors (NOT brushes). And note that I also need some colors with a specific alpha-channel applied to them (matching 26% opacity). I hope something is already available to get this, otherwise a custom
MarkupExtension
could be an option.Changes:
Changes
RatingBar.Value
to a double which is coerced into a multiple of 0.5 and forced to stay within the Min/Max bounds of theRatingBar
. The "half selected" visual appearance is accomplished by using a (gradient)Brush
onTextBlock.Foreground
which is either fully opaque (selected), a mix of fully opaque and semi-transparent (half-way selected), or completely semi-transparent (not selected). These gradients/brushes are where I need to access theming colors.Implementation respects
RatingBar.Orientation
, however I am not entirely sure (ie. I haven't tested) whether it works in RTL layout.